/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package assisisw.smartcal.weathersubsystem;

import assisisw.smartcal.weathersubsystem.exceptions.ExternalServiceException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Scanner;
import javax.ejb.Stateless;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Francesco
 */
@Stateless
public class JerseyWorldWeatherOnlineDataRetriever implements IExternalWeatherDataRetriever
{

    // Static Fields
    
    /***/
    private static final String BASE_URL = "http://api.worldweatheronline.com/free/v2/" ;
    
    /***/
    private static final String KEY = "0cd56f5b82ed30c2a4ae047bbcef9" ;
    
    /***/
    private static final String FORMAT = "csv" ;
    
    /***/
    private static final int NUMBER_OF_HOURS = 3 ;
    
    // Instance Fields
    
    /***/
    private Client client ;
    
    /***/
    private DocumentBuilderFactory docBuildFact ;
    
    /***/
    private DocumentBuilder docBuilder ;
    
    // Instance Methods
    
    /***/
    public JerseyWorldWeatherOnlineDataRetriever () throws ExternalServiceException 
    {
        try 
        {
            client = ClientBuilder.newClient ();
            docBuildFact = DocumentBuilderFactory.newInstance () ;
            docBuilder = docBuildFact.newDocumentBuilder();
        } 
        catch (ParserConfigurationException ex) 
        {
            throw new ExternalServiceException ( "XML Mapping Structure Generation Error" ) ;
        }
    }
    
    /**
     * AS THE SUPER'S ONE.
     */
    @Override
    public Iterable < WeatherData > retrieve(String city, String country) throws ExternalServiceException 
    {
        Response r ;
        String rawXML ;
        Iterable < WeatherData > res ;
        r = client.target ( BASE_URL+"weather.ashx?q="+city+"&format="+FORMAT+"&cc=false&num_of_days=5&tp="+NUMBER_OF_HOURS+"&key="+KEY).request(MediaType.APPLICATION_XML_TYPE).get();
        rawXML = r.readEntity(String.class);
        System.out.println(rawXML);
        res = parseCSV(rawXML,city);
        return res ;
    }

    private Iterable < WeatherData > parseCSV ( String csvContent , String location ) 
    {
        Collection < WeatherData > res ;
        res = new LinkedList <> () ;
        String currentLine ;
        String [] data ;
        String [] rawTime ;
        String date ;
        String time ;
        String tempC ;
        String desc ;
        WeatherData entry ;
        Calendar c1 ;
        Calendar c2 ;
        int hours ;
        int minutes ;
        try ( Scanner scanner = new Scanner ( csvContent ) )
        {
            while ( scanner.hasNextLine () && scanner.nextLine ().charAt ( 0 ) == '#' ) ;   // skip explanation
            scanner.nextLine () ;   // skip first entry
            scanner.nextLine () ;   // skip second entry
            while ( scanner.hasNextLine () )
            {
                currentLine = scanner.nextLine () ;
                data = currentLine.split(",");
                if ( data.length > 10 )
                {
                    date = data [ 0 ] ;
                    time = data [ 1 ] ;
                    tempC = data [ 2 ] ;
                    desc = data [ 10 ] ;
                    c1 = Calendar.getInstance () ;
                    c2 = Calendar.getInstance () ;
                    rawTime = date.split ( "-" ) ;
                    hours = time.length () == 4 ? Integer.parseInt ( time.substring ( 0 , 2 ) ) : Integer.parseInt ( time.substring ( 0 , 1 ) ) ;
                    minutes = Integer.parseInt ( time.substring ( time.length () - 2 ) ) ;
                    c1.set ( Integer.parseInt( rawTime [0] ) , Integer.parseInt ( rawTime[1] ) , Integer.parseInt ( rawTime [2] ) , hours , minutes ) ;
                    c2.set ( Integer.parseInt( rawTime [0] ) , Integer.parseInt ( rawTime[1] ) , Integer.parseInt ( rawTime [2] ) , hours + 3 > 24 ? 24 : hours + 3 , minutes ) ;
                    entry = new WeatherData ( location , c1.getTime(), c2.getTime() , Integer.parseInt ( tempC ) , desc ) ;
                    res.add ( entry ) ;
                }
            }
        }
        
        return res ;
    }
    
    /**
     * @param xmlContent 
     * @return
     * @throws SAXException
     * @throws IOException
     */
    private Iterable < WeatherData > parseXML ( String xmlContent ) throws SAXException, IOException 
    {
        System.out.println(xmlContent);
        Collection < WeatherData > res ;
        NodeList n ;
        Document doc ;
        Element e ;
        String rawDate ;
        NodeList hourly ;
        res = new LinkedList <> () ;
        doc = docBuilder.parse ( new ByteArrayInputStream ( xmlContent.getBytes( StandardCharsets.UTF_8 ) ) ) ;
        n = doc.getDocumentElement().getElementsByTagName("weather");   // now here there should be all the weather nodes
        for ( int i = 0 ; i < n.getLength() ; i ++ )    // for each weather info
        {
            e = ( Element ) n.item ( i ) ;  // Now e holds the element, cycle over all the hourly
            rawDate = e.getElementsByTagName("date").item(0).getTextContent () ;    // date equals for every hour
            hourly = e.getElementsByTagName("hourly");  // every hour contains an entry , cycle over it
            System.out.println(rawDate);
            for ( int j = 0 ; j < hourly.getLength () ; j ++ )
            {
               String s1 = e.getElementsByTagName ( "time" ).item(0).getTextContent () ;  // the start time
               System.out.println(s1);
               String s2 = e.getElementsByTagName ( "tempC" ).item(0).getTextContent () ;   // the temperature
               System.out.println(s2);
               String s3 = e.getElementsByTagName ( "weatherDesc" ).item ( 0 ).getTextContent () ;  // a textual desc.
               System.out.println(s3);
            }            
        }
        return res ;
    }
       
}
